package sequence_list

import (
	myErr "data_structure/error"
)

type sequenceList[T any] struct {
	cap    uint
	length uint
	data   []T
}

// New 创建并返回一个新的泛型顺序表。
// 该函数通过指定的容量cap，初始化一个空的顺序表。
// 参数:
//
//	T: 泛型参数，表示顺序表中元素的类型。
//	cap: uint类型，指定顺序表的初始容量。
//
// 返回值:
//
//	*sqList[T]: 返回指向初始化后的顺序表的指针。
func New[T any](cap uint) *sequenceList[T] {
	// 使用指定的容量cap创建一个新的sqList实例。
	// 初始化时，数据切片为空（长度为0），但预分配了cap个元素的空间以减少后续扩容操作。
	return &sequenceList[T]{
		cap:  cap,
		data: make([]T, 0, cap),
	}
}

// Length 方法返回当前顺序表的长度。
// 此方法不接受任何参数，并返回一个 uint 类型的值，代表顺序表中元素的数量。
func (sl *sequenceList[T]) Length() uint {
	return sl.length
}

// IsEmpty 判断顺序表是否为空。
//
// 返回值:
//
//	bool: 返回 true 如果列表是空的，否则返回 false。
func (sl *sequenceList[T]) IsEmpty() bool {
	return sl.length == 0
}

// Clear 方法用于清空 sqList 中的所有元素。
// 它重置了列表的长度，并清空了其数据内容，但保留了原有的容量。
// 这确保了 sqList 可以再次使用而无需重新分配内存。
func (sl *sequenceList[T]) Clear() {
	sl.length = 0
	sl.data = make([]T, 0, sl.cap)
}

// Insert 方法用于在指定位置插入数据到广场列表中
//
// 参数:
//
//	index: 插入数据的位置，有效范围为 1 到 sl.length+1
//	data: 需要插入的数据
//
// 返回值:
//
//	错误对象，如果插入位置超出范围则返回 ErrorIndexOutOfRange，否则返回 nil
func (sl *sequenceList[T]) Insert(index uint, data T) error {
	// 检查插入位置是否有效以及当前列表是否有足够的容量进行插入操作
	if sl.length+1 > sl.cap || index > sl.length+1 || index == 0 {
		return myErr.ErrorIndexOutOfRange
	}
	// 重新组织数据，将新数据插入到指定位置
	sl.data = append(sl.data[:index-1], append([]T{data}, sl.data[index-1:]...)...)
	// 更新列表长度
	sl.length++
	return nil
}

// Remove 方法从 sqList 中移除指定索引的元素。
//
// 参数:
//
//	index: 要移除的元素在列表中的索引位置。
//
// 返回值:
//
//	T: 被移除的元素的值。
//	error: 如果索引超出有效范围，则返回错误；否则返回 nil。
func (sl *sequenceList[T]) Remove(index uint) (T, error) {
	// 初始化一个 T 类型的零值。
	var zeroValue T

	// 检查索引是否超出范围或等于0，如果是，返回错误。
	if index > sl.length || index == 0 {
		return zeroValue, myErr.ErrorIndexOutOfRange
	}

	// 保存要移除的元素值。
	tmp := sl.data[index-1]

	// 从列表中移除指定索引的元素。
	sl.data = append(sl.data[:index-1], sl.data[index:]...)

	// 更新列表长度。
	sl.length--

	// 返回被移除的元素值和 nil 错误。
	return tmp, nil
}

// GetByIndex 根据指定索引获取顺序表中的元素。
//
// 参数:
//
//	index - 请求元素的索引，必须在列表的有效范围内。
//
// 返回值:
//   - 列表中指定索引位置的元素。
//   - 如果索引超出范围，则返回错误ErrorIndexOutOfRange。
func (sl *sequenceList[T]) GetByIndex(index uint) (T, error) {
	// 初始化一个T类型的零值。
	var zeroValue T

	// 检查索引是否超出有效范围（0 或者大于列表长度）。
	// 如果是，则返回零值和错误ErrorIndexOutOfRange。
	if index == 0 || index > sl.length {
		return zeroValue, myErr.ErrorIndexOutOfRange
	}

	// 返回索引对应的实际元素。
	// 注意索引需要减1，因为Go的切片索引是从0开始的。
	return sl.data[index-1], nil
}
